package value

import (
	"database/sql"
	errors2 "gitee.com/go-web-2/orm_framework/errors"
	"gitee.com/go-web-2/orm_framework/session/model"
	"gitee.com/go-web-2/orm_framework/utils"
	"reflect"
	"strings"
)

type ReflectValue struct {
	model *model.Model
	Val   reflect.Value
}

func (r *ReflectValue) SetColumns(rows *sql.Rows, quote string) error {
	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	if len(cols) != len(r.model.ColToFieldMap) {
		return errors2.ErrCountColumns
	}

	valElems := make([]reflect.Value, 0, len(cols))
	valInterfaces := make([]any, 0, len(cols))

	for _, colName := range cols {
		colName = strings.ReplaceAll(colName, quote, "")
		field, ok := r.model.FieldToColMap[colName]
		if !ok {
			return errors2.ErrNotFoundColumn(colName)
		}
		val := reflect.New(field.Typ)
		valElems = append(valElems, val.Elem())
		valInterfaces = append(valInterfaces, val.Interface())
	}

	err = rows.Scan(valInterfaces...)
	if err != nil {
		return err
	}

	for i, colName := range cols {
		colName = strings.ReplaceAll(colName, quote, "")
		field := r.model.FieldToColMap[colName]
		fd := r.Val.FieldByName(field.ColName)
		if fd.CanSet() {
			fd.Set(valElems[i])
		}
	}
	return nil
}

// NewReflectValue val必须是指向结构体的一级指针
func NewReflectValue(val any, model *model.Model) (Value, error) {
	if reflect.TypeOf(val).Kind() != reflect.Ptr {
		return nil, errors2.ErrNotPointToStruct
	}
	return &ReflectValue{
		model: model,
		Val:   reflect.ValueOf(val).Elem(),
	}, nil
}

var _ Creator = NewReflectValue
var _ Value = (*ReflectValue)(nil)

type ReflectValues struct {
	Vals    reflect.Value // []Slice
	valType reflect.Type  // 指向结构体的一级指针
	model   *model.Model
	Creator Creator
}

func (r *ReflectValues) SetValues(rows *sql.Rows, quote string) error {
	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	if len(cols) != len(r.model.ColToFieldMap) {
		return errors2.ErrCountColumns
	}

	for rows.Next() {
		valInstance := reflect.New(r.valType).Interface()
		var value Value
		value, err = r.Creator(valInstance, r.model)
		if err != nil {
			return err
		}
		err = value.SetColumns(rows, quote)
		if err != nil {
			return err
		}
		r.Vals.Set(reflect.Append(r.Vals, reflect.ValueOf(valInstance)))
	}
	defer rows.Close()
	return nil
}

func (r *ReflectValue) Field(colName string) (any, error) {
	return r.Val.FieldByName(colName).Interface(), nil
}

type Opt func(r *ReflectValues)

func WithValueCreator(creator Creator) Opt {
	return func(r *ReflectValues) {
		r.Creator = creator
	}
}

// NewReflectValues vals必须是指向结构体一级指针的切片的指针，示例: arr := make([]*test, 0, 5), 需要传入&arr // 传入arr而不是&arr会导致修改arr无法生效
func NewReflectValues(vals any, model *model.Model, opts ...Opt) (*ReflectValues, error) {
	elem, err := utils.ValidateValsType(vals)
	if err != nil {
		return nil, err
	}

	r := &ReflectValues{
		Vals:    reflect.ValueOf(vals).Elem(),
		valType: elem,
		model:   model,
		Creator: NewReflectValue,
	}
	for _, opt := range opts {
		opt(r)
	}
	return r, nil
}
